package br.com.statizo.financeiro.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import br.com.snoghert.persistence.entity.impl.SAbstractEntity;

@Entity(name="Lancamento")
public class Lancamento extends SAbstractEntity{

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="id_lancamento")
	private Long id;

	@Column(name="dt_div",nullable=false)
	@Temporal(TemporalType.DATE)
	private Calendar dataDivida;

	@Column(name="dt_pgto",nullable=false)
	@Temporal(TemporalType.DATE)
	private Calendar dataPagamento;

	@Column(name="vl_lancamento",nullable=false)
	private double valor;
	
	@Column(name="ds_complemento",nullable=false)
	private String complemento;

	@ManyToOne(fetch=FetchType.EAGER,optional=false)
	@JoinColumn(name="id_tipo",nullable=false)
	private TipoLancamento tipo;

	@ManyToOne(fetch=FetchType.EAGER,optional=true)
	@JoinColumn(name="id_tipo_pgto",nullable=true)
	private TipoPagamento tipoPagamento;

	@ManyToOne(fetch=FetchType.EAGER,optional=true)
	@JoinColumn(name="id_recurso",nullable=true)
	private Lancamento recurso;

	@ManyToOne(fetch=FetchType.EAGER,optional=true)
	@JoinColumn(name="id_pri_parc",nullable=true)
	private Lancamento primeiraParcela;

	@OneToMany(fetch=FetchType.EAGER,mappedBy="primeiraParcela",cascade=CascadeType.ALL)
	private List<Lancamento> parcelasVinculadas = new ArrayList<>();

	@Column(name="fl_controle_gastos")
	private boolean controleGastos;

	@OneToMany(fetch=FetchType.LAZY,mappedBy="recurso",cascade=CascadeType.ALL)
	private List<Lancamento> controles = new ArrayList<>();
	
	@Column(name="fl_rec_aloc")
	private boolean recursoAlocado;
	
	@Column(name="st_pago",nullable=false)
	private boolean pago;
	
	@ManyToOne(fetch=FetchType.EAGER, optional=true)
	@JoinColumn(name="id_cc", nullable=true)
	private ContaTransferencia contaTransferencia;
	
	@Transient
	private transient String informacao;
	
	
	public boolean isParcela(){
		return isPrimeiraParcela() || isParcelaDerivada();
	}
	
	public boolean isParcelaDerivada(){
		return primeiraParcela != null;
	}
	
	public boolean isPrimeiraParcela(){
		return primeiraParcela == null && parcelasVinculadas.size() > 0;
	}
	
	public boolean isRecursoAlocado() {
		return recursoAlocado;
	}
	
	public void setRecursoAlocado(boolean recursoAlocado) {
		this.recursoAlocado = recursoAlocado;
	}
	

	@Override
	public Serializable getId() {
		return id;
	}


	public void setId(Long id) {
		this.id = id;
	}
	
	public Calendar getDataDivida() {
		return dataDivida;
	}



	public void setDataDivida(Calendar dataLancamento) {
		this.dataDivida = dataLancamento;
	}



	public Calendar getDataPagamento() {
		return dataPagamento;
	}



	public void setDataPagamento(Calendar dataRealizacao) {
		this.dataPagamento = dataRealizacao;
	}



	public String getComplemento() {
		return complemento;
	}



	public void setComplemento(String complemento) {
		this.complemento = complemento;
	}



	public TipoPagamento getTipoPagamento() {
		return tipoPagamento;
	}



	public void setTipoPagamento(TipoPagamento cartao) {
		this.tipoPagamento = cartao;
	}



	public Lancamento getRecurso() {
		return recurso;
	}



	public void setRecurso(Lancamento recurso) {
		this.recurso = recurso;
	}



	public Lancamento getPrimeiraParcela() {
		return primeiraParcela;
	}



	public void setPrimeiraParcela(Lancamento primeiraParcela) {
		this.primeiraParcela = primeiraParcela;
	}



	public List<Lancamento> getParcelasVinculadas() {
		return parcelasVinculadas;
	}



	public void setParcelasVinculadas(List<Lancamento> parcelasVinculadas) {
		this.parcelasVinculadas = parcelasVinculadas;
	}


	public void setControles(List<Lancamento> controles) {
		this.controles = controles;
	}
	
	
	public List<Lancamento> getControles() {
		return controles;
	}
	

	public boolean isPago() {
		return pago;
	}



	public void setPago(boolean pago) {
		this.pago = pago;
	}


	public TipoLancamento getTipo() {
		return tipo;
	}

	public void setTipo(TipoLancamento tipo) {
		this.tipo = tipo;
	}


	public boolean isControleGastos(){
		return this.controleGastos;
	}

	public void setControleGastos(boolean controleGastos) {
		this.controleGastos = controleGastos;
	}

	public void setContaTransferencia(ContaTransferencia contaTransferencia) {
		this.contaTransferencia = contaTransferencia;
	}
	
	public ContaTransferencia getContaTransferencia() {
		return contaTransferencia;
	}
	
	public double getValor() {
		return valor;
	}
	
	public void setValor(double valor) {
		this.valor = valor;
	}
	
	public String getDescricao(){
		return tipo.getDescricao() + " - " + getComplemento();
	}
	
	
	public GrupoLancamento getGrupo(){
		if(tipo == null) return null;
		return tipo.getGrupo();
	}
	
	
	public boolean isReceita(){
		return is(GrupoLancamento.RECEITA);
	}
	
	public boolean isInvestimento(){
		return is(GrupoLancamento.INVESTIMENTO);
	}
	
	public boolean isDespesaFixa(){
		return is(GrupoLancamento.DESPESA_FIXA);
	}
	
	public boolean isDespesaVariavel(){
		return is(GrupoLancamento.DESPESA_VARIAVEL);
	}
	
	public boolean isDespesaExtra(){
		return is(GrupoLancamento.DESPESA_EXTRA);
	}
	
	public boolean isDespesaAdicional(){
		return is(GrupoLancamento.DESPESA_ADICIONAL);
	}	
	
	public boolean isCartao(){
		if(this.tipoPagamento == null)
			return false;
		return this.tipoPagamento.isCartaoCredito();
	}
	
	protected boolean is(GrupoLancamento grupo){
		return tipo.getGrupo().equals(grupo);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		Lancamento other = (Lancamento) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}
	
	
	
	public String getInformacao() {
		return informacao;
	}
	
	public void setInformacao(String informacao) {
		this.informacao = informacao;
	}

	@Override
	public String toString() {
		return "Lancamento [id=" + id + ", dataDivida=" + dataDivida
				+ ", dataPagamento=" + dataPagamento + ", valor=" + valor
				+ ", complemento=" + complemento + ", tipo=" + tipo
				+ ", tipoPagamento=" + tipoPagamento + ", recurso=" + recurso
				+ ", primeiraParcela=" + primeiraParcela
				+ ", parcelasVinculadas=" + parcelasVinculadas
				+ ", controleGastos=" + controleGastos + ", controles="
				+ controles + ", recursoAlocado=" + recursoAlocado + ", pago="
				+ pago + ", contaTransferencia=" + contaTransferencia + "]";
	}
	

	

}